home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
mac
/
files
/
t_sys5
/
unixcpio.gz
/
unixnet.cpio
/
dirutil.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-11
|
15KB
|
668 lines
/* dirutil.c - MS-DOS directory reading routines
*
* Bdale Garbee, N3EUA, Dave Trulli, NN2Z, and Phil Karn, KA9Q
* Directory sorting by Mike Chepponis, K3MC
* adapted for ATARI ST & cleaned up by Rob Janssen, PE1CHL
* adapted for Lattice C by Walter Doerr, DG2KK
*/
#include <stdio.h>
#ifndef LATTICE
#include <ctype.h> /* DG2KK: force Lattice to use library func. */
#endif
#ifdef LATTICE
#define S_IJHID 2
#define S_IJSYS 4
#define S_IJDIR 0x10
struct stat {
char st_mode; /* that's all we need */
};
#else /* not LATTICE */
#ifdef __TURBOC__
#include <dos.h>
#include <sys\stat.h>
#else /* not LATTICE and not TURBOC */
#include <stat.h>
#endif
#endif
#ifdef MSDOS
#define IS_ERROR == -1 /* error return from MSDOS */
#endif
#ifdef __TURBOC__
#define ST_RDONLY 0x01 /* Read only attribute */
#define ST_HIDDEN 0x02 /* Hidden file */
#define ST_SYSTEM 0x04 /* System file */
#define ST_LABEL 0x08 /* Volume label */
#define ST_DIRECT 0x10 /* Directory */
#define ST_ARCH 0x20 /* Archive */
int dos(unsigned ah,
unsigned bx,
unsigned cx,
void *dx,
unsigned si,
unsigned di)
{
union REGS regs;
regs.h.ah = ah;
regs.x.bx = bx;
regs.x.cx = cx;
regs.x.dx = dx;
regs.x.si = si;
regs.x.di = di;
intdos(®s, ®s);
if (regs.x.cflag) return -1;
return 0;
}
#define bdos(x, y) bdos(x, (unsigned) y, 0)
#endif /* TURBOC */
#ifdef ATARI_ST
#define IS_ERROR < 0 /* error return from gemdos */
#include <osbind.h> /* os interface defines */
#define bdos gemdos /* Atari OS call */
#define dos(a,b,c,d,e,f) gemdos(a,d,c) /* only valid for FIND func */
#define st_attr st_mode /* what's in a name? */
#define ST_HIDDEN S_IJHID /* Hidden from search */
#define ST_SYSTEM S_IJSYS /* System, hidden from search */
#define ST_DIRECT S_IJDIR /* Directory */
#endif
#include "global.h"
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE !(FALSE)
#endif
#define REGFILE (ST_HIDDEN|ST_SYSTEM|ST_DIRECT)
#define SET_DTA 0x1a
#define FIND_FIRST 0x4e
#define FIND_NEXT 0x4f
struct dirent {
char rsvd[21];
char attr;
short ftime;
short fdate;
long fsize;
char fname[13];
};
#define NULLENT (struct dirent *)0
struct dirsort {
struct dirsort *prev;
struct dirsort *next;
struct dirent *direntry;
};
#define NULLSORT (struct dirsort *)0
/* Create a directory listing in a temp file and return the resulting file
* descriptor. If full == 1, give a full listing; else return just a list
* of names.
*/
FILE *
dir(path,full)
char *path;
int full;
{
FILE *fp,*tmpfile();
if ((fp = tmpfile()) != NULLFILE)
{
getdir(path,full,fp);
/* This should be rewind(), but Aztec doesn't have it */
#if (ATARI_ST && MWC)
vseek(fp,0L,0);
#else
fseek(fp,0L,0);
#endif
}
return fp;
}
/* wildcard filename lookup */
filedir(name,times,ret_str)
char *name;
int times;
char *ret_str;
{
register char *cp,*cp1;
static struct dirent sbuf;
bdos(SET_DTA,&sbuf); /* Set disk transfer address */
/* Find matching file */
if(dos(times == 0 ? FIND_FIRST:FIND_NEXT,0,REGFILE,name,0,0) IS_ERROR)
sbuf.fname[0] = '\0';
/* Copy result to output, forcing to lower case */
for(cp = ret_str,cp1 = sbuf.fname; cp1 < &sbuf.fname[13] && *cp1 != '\0';)
*cp++ = (char)tolower(*cp1++); /* DG2KK: added (char) */
*cp = '\0';
}
/* Change working directory */
docd(argc,argv)
int argc;
char *argv[];
{
char dirname[128];
#ifdef MSDOS
char *getcwd();
#endif
if(argc > 1){
if(chdir(argv[1]) IS_ERROR){
printf("Can't change directory\n");
return 1;
}
}
#ifdef MSDOS
if(getcwd(dirname,0) != NULLCHAR){
printf("\\%s\n",dirname);
}
#endif
#ifdef ATARI_ST
if (Dgetpath(dirname,0) == 0){
printf("%c:%s%s\n",(char) Dgetdrv()+'A',
(*dirname? "" : "\\"),dirname);
}
#endif
return 0;
}
/* List directory to console. [-/]w option selects "wide" format */
dodir(argc,argv)
int argc;
char *argv[];
{
char *path;
int full = 1;
if (argc > 1 &&
(argv[1][0] == '-' || argv[1][0] == '/') && argv[1][1] == 'w')
{
full = -1;
argv++;
argc--;
}
if(argc >= 2){
path = argv[1];
} else {
path = "*.*";
}
getdir(path,full,stdout);
return 0;
}
/* do a directory list to the stream
* full = 0 -> short form, 1 is long, -1 is multi-column short
*/
static
getdir(path,full,file)
char *path;
int full;
FILE *file;
{
struct dirent sbuf;
struct stat statbuf;
char *cp,*cp1; /* !!!!!!! was: register */
char dirtmp[20];
int command = FIND_FIRST;
int i = 0;
int cflag = 0;
int n = 0;
char line_buf[50]; /* for long dirlist */
struct dirsort *head, *here, *new;
struct dirent *de;
void dir_sort(), format_dir(), format_fname(), diskfree(), free_clist();
int malloc_lost = FALSE;
/* Root directory is a special case */
if(path == NULLCHAR || *path == '\0' || strcmp(path,"\\") == 0)
path = "\\*.*";
/* If arg is a directory, append "\*.*" to it.
* This is tricky, since the "stat" system call actually
* calls the DOS "find matching file" function. The stat
* call therefore returns the attributes for the first matching
* entry in the directory. If the arg already ends in *.*,
* stat will match the . entry in the directory and indicate
* that the argument is a valid directory name. Hence the
* heuristic check for '*' in the file name. Kludge...
*/
#ifdef __TURBOC__
else if(stat(path,&statbuf) != -1
&& (statbuf.st_mode & S_IFDIR)
&& index(path,'*') == NULLCHAR) {
#else
else if(index(path,'*') == NULLCHAR
&& stat(path,&statbuf) != -1
&& (statbuf.st_attr & ST_DIRECT)) {
#endif
if((cp = malloc(strlen(path) + 10)) == NULLCHAR)
return -1;
sprintf(cp,"%s%c%s",path,'\\',"*.*");
path = cp;
cflag = 1;
}
head = NULLSORT; /* No head of chain yet... */
for(;;){
bdos(SET_DTA,&sbuf); /* Set disk transfer address */
if(dos(command, 0, REGFILE, path, 0, 0) IS_ERROR)
break;
command = FIND_NEXT; /* Got first one already... */
if(sbuf.fname[0] != '.'){
/* nuke "." and ".." */
n++; /* One more entry */
new = (struct dirsort *) malloc(sizeof(struct dirsort));
if(new == NULLSORT)
malloc_lost = TRUE;
de = (struct dirent *)malloc(sizeof(struct dirent));
if(de == NULLENT)
malloc_lost = TRUE;
if(malloc_lost){
/* Clean up and call other routine */
if(new)free(new);
free_clist(head);
return getdir_nosort(path,full,file);
}
*de = sbuf; /* Copy contents of directory entry struct */
/* Fix up names for easier sorting... pain! */
strcpy(de->fname," "); /* 11 blanks */
cp = sbuf.fname;
cp1 = de->fname;
do *cp1++ = *cp++; while (*cp && *cp != '.');
if(*cp++){
/* If there is an extension */
cp1 = &(de->fname[8]);
do *cp1++ = *cp++; while (*cp);
}
if(!(int)head){
/* Make the first one */
here = head = new;
head->prev = head->next = NULLSORT;
} else {
/* Link on next one */
new->next = NULLSORT;
new->prev = here;
here->next = new;
here = new;
}
new->direntry = de;
} /* IF on "." */
} /* infinite FOR loop */
if(head)
dir_sort(head); /* Make a nice, sorted list */
here = head;
if(here)
if(full > 0){
do {
format_dir(line_buf,here->direntry);
fprintf(file,"%s%s",line_buf,(i^=1) ? " " : "\r\n");
} while (here = here->next);
if(i & 1)
fprintf(file,"\r\n");
}
else {
/* This is the short form */
do {
format_fname(dirtmp,here->direntry->fname,
here->direntry->attr);
fprintf(file,"%-15s%s",dirtmp,((full && ++i % 5)?"":"\r\n"));
} while (here = here->next);
if(full && i % 5)
fprintf(file,"\r\n");
}
/* Give back all the memory we temporarily needed... */
free_clist(head);
if(full > 0){
/* Provide additional information only on DIR */
if (isalpha(*path) && path[1] == ':') /* detect A: drivespec */
diskfree(file,*path & 0x1f,n);
else
diskfree(file,0,n);
}
if(cflag)
free(path);
return 0;
} /* getdir */
static
getdir_nosort(path,full,file)
char *path;
int full;
FILE *file;
{
struct dirent sbuf;
struct stat statbuf;
register char *cp;
char dirtmp[20];
int command = FIND_FIRST;
int i = 0;
int cflag = 0;
char line_buf[50]; /* for long dirlist */
void format_fname(),format_dir(),diskfree();
int n = 0; /* Number of directory entries */
/* Root directory is a special case */
if(path == NULLCHAR || *path == '\0' || strcmp(path,"\\") == 0)
path = "\\*.*";
/* If arg is a directory, append "\*.*" to it.
* This is tricky, since the "stat" system call actually
* calls the DOS "find matching file" function. The stat
* call therefore returns the attributes for the first matching
* entry in the directory. If the arg already ends in *.*,
* stat will match the . entry in the directory and indicate
* that the argument is a valid directory name. Hence the
* heuristic check for '*' in the file name. Kludge...
*/
#ifdef __TURBOC__
else if(stat(path,&statbuf) != -1
&& (statbuf.st_mode & S_IFDIR)
&& index(path,'*') == NULLCHAR) {
#else
else if(index(path,'*') == NULLCHAR
&& stat(path,&statbuf) != -1
&& (statbuf.st_attr & ST_DIRECT)) {
#endif
if((cp = malloc(strlen(path) + 10)) == NULLCHAR)
return -1;
sprintf(cp,"%s%c%s",path,'\\',"*.*");
path = cp;
cflag = 1;
}
for(;;){
bdos(SET_DTA,&sbuf); /* Set disk transfer address */
if(dos(command,0,REGFILE,path,0,0) IS_ERROR)
break;
command = FIND_NEXT; /* Got first one already... */
if(sbuf.fname[0] != '.'){ /* nuke "." and ".." */
if(full > 0){
n++; /* Count 'em */
format_dir(line_buf,&sbuf);
fprintf(file,"%s%s",line_buf,(i^=1) ? " " : "\n");
} else { /* is short form */
format_fname(dirtmp,sbuf.fname,sbuf.attr);
fprintf(file,"%-15s%s",dirtmp,(full && (++i % 5)?"":"\n"));
}
}
}
if(full > 0){
if(i)
fprintf(file,"\n");
if (isalpha(*path) && path[1] == ':') /* detect A: drivespec */
diskfree(file,*path & 0x1f,n);
else
diskfree(file,0,n);
}
else
if(i % 5)
fprintf(file,"\n");
if(cflag)
free(path);
return 0;
}
static
void
diskfree (file,drv,nfiles)
FILE *file;
int drv;
int nfiles;
{
#ifdef MSDOS
unsigned short ax,bx,cx,dx;
void isfree();
#endif
#ifdef ATARI_ST
struct { unsigned long di_free,di_many,di_ssize,di_spau; } disk_info;
#endif
unsigned long free_bytes = 0, total_bytes = 0;
char s_free[11], s_total[11];
void commas();
fflush(stdout); /* function takes a short while... */
#ifdef MSDOS
/* Provide additional information */
ax = 0x3600; /* AH = 36h, AL = 0 (AL not used) */
dx = drv; /* Default drive */
isfree(&ax,&bx,&cx,&dx);
if (ax != 0xffff)
{
free_bytes = (unsigned long)ax * (unsigned long)cx;
total_bytes = free_bytes * (unsigned long)dx;
free_bytes *= (unsigned long)bx;
}
#endif
#ifdef ATARI_ST
if (Dfree(&disk_info,drv) == 0)
{
free_bytes = disk_info.di_spau * disk_info.di_ssize;
total_bytes = free_bytes * disk_info.di_many;
free_bytes *= disk_info.di_free;
}
#endif
sprintf(s_free,"%ld",free_bytes); commas(s_free);
sprintf(s_total,"%ld",total_bytes); commas(s_total);
if(nfiles)
fprintf(file,"%d",nfiles);
else
fprintf(file,"No");
fprintf(file," file%s. %s bytes free. Disk size %s bytes.\r\n",
(nfiles==1? "":"s"),s_free,s_total);
}
/*
* Return a string with commas every 3 positions.
* If malloc() fails, return original string unmodified.
* else the original string is replace with the string with commas.
*
* The caller must be sure that there is enough room for the resultant
* string.
*
*
* k3mc 4 Dec 87
* pe1chl 3 Feb 88 europeans would use periods...
*/
#ifndef THSEP
#define THSEP ','
#endif
void
commas(dest)
char *dest;
{
char *src, *core; /* Place holder for malloc */
unsigned cc; /* The comma counter */
unsigned len;
len = strlen(dest);
if( (core = src = (char *)malloc(len+1)) == NULLCHAR)
return;
strcpy(src,dest); /* Make a copy, so we can muck around */
cc = (len-1)%3 + 1; /* Tells us when to insert a comma */
while(*src != '\0'){
*dest++ = *src++;
if( ((--cc) == 0) && *src ){
*dest++ = THSEP; cc = 3;
}
}
free(core);
*dest = '\0';
}
/*
* This insertion sort adapted from "Writing Efficient Programs" by Jon Louis
* Bentley, Prentice-Hall 1982, ISBN 0-13-070244-X (paperback) p. 65
*
* Run Time (sec) = K * N^2, where K = 21e-6 on my turbo XT clone (SI=2.6).
* This could be improved to perhaps K * N * log2(N) using Quicksort, but,
* as Bentley points out, this insertion sort is actually faster for small
* values of N. His "best" sorting algorithm uses an insertion sort/Quicksort
* hybrid, with the "cutoff" value being about 30 elements.
*
* I have opted for the straight insertion sort because it is quite simple,
* provably correct, and not a terrible performer when N < 1000, which is the
* case for most directories.
*/
static
void
dir_sort(head)
struct dirsort *head;
{
struct dirsort *here, *backtrack;
struct dirent *de_temp;
for(here = head->next; here != NULLSORT; here = here->next){
backtrack = here;
de_temp = here->direntry;
while(backtrack->prev
&& strcmp(de_temp->fname,backtrack->prev->direntry->fname)<0){
backtrack->direntry = backtrack->prev->direntry;
backtrack = backtrack->prev;
}
backtrack->direntry = de_temp;
}
}
static
void
format_dir (line_buf,sbuf)
char *line_buf;
struct dirent *sbuf;
{
char dirtmp[20];
char cbuf[20],cbuf1[20];
format_fname(dirtmp,sbuf->fname,sbuf->attr);
sprintf(line_buf,"%-13s",dirtmp);
if(sbuf->attr & ST_DIRECT)
strcat(line_buf," ");/* 11 spaces */
else {
sprintf(cbuf,"%ld",sbuf->fsize);
commas(cbuf);
sprintf(cbuf1,"%10s ",cbuf);
strcat(line_buf,cbuf1); /* Do filesize */
}
sprintf(cbuf,"%2d:%02d %2d/%02d/%02d",
(sbuf->ftime >> 11) & 0x1f, /* hour */
(sbuf->ftime >> 5) & 0x3f, /* minute */
(sbuf->fdate >> 5) & 0xf, /* month */
(sbuf->fdate ) & 0x1f, /* day */
(sbuf->fdate >> 9) + 80); /* year */
strcat(line_buf,cbuf);
}
static
void
format_fname(dest,src,attr)
char *dest, *src;
char attr;
{
char *cp = src+8;
int loop_counter;
for(loop_counter=0; loop_counter<8; loop_counter++){
*dest++ = (char)tolower(*src++); /* DG2KK: (char) */
if(*src == ' ')break;
}
if(cp[0] != ' ' || cp[1] != ' ' || cp[2] != ' '){ /* There is an extension */
*dest++ = '.';
for(loop_counter=0; loop_counter<3; loop_counter++){
*dest++ = (char)tolower(*cp++); /* DG2KK: (char) */
if(*cp == ' ')break;
}
}
if(attr & ST_DIRECT)*dest++ = '\\';
*dest = '\0';
}
static
void
free_clist(head)
struct dirsort *head;
{
struct dirsort *here;
here = head;
if(here)do{
free(here->direntry);
if(head != here){
free(head);
head = here;
}
} while (here = here->next);
if(head != here){
free(head);
head = here;
}
}
#ifdef LATTICE /* DG2KK: Lattice doesn't know a thing about stat */
int
stat(name,buf)
char *name;
struct stat *buf;
{
static struct dirent sbuf;
static struct stat statbuf;
int error;
gemdos(SET_DTA, &sbuf);
error = gemdos(FIND_FIRST, name, REGFILE); /* look for directories */
if (error)
return(-1); /* caller insists on -1 */
statbuf.st_attr = sbuf.attr;
return 0;
}
#endif